home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…stman Always Clicks Twice / ADC Developer CD (1993-01) (''The Postman Always Clicks Twice'')_iso / Dev.CD 199301.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / DTS.Lib / CtlHandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-22  |  18.0 KB  |  642 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        ctlhandler.c
  6. ** Written by:  Eric Soldan
  7. **
  8. ** Copyright © 1991 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* This code implements the new 7.0 human-interface standards for both
  13. ** TextEdit and List controls.  These standards include the following features:
  14. **
  15. ** 1) Tabbing between TextEdit and List controls within a window.
  16. ** 2) Displaying what item is active.  The active TextEdit item is indicated
  17. **    by either a blinking caret, or a selection range.
  18. ** 3) List positioning via the keyboard.  Entries on the keyboard automatically
  19. **    select and display the closest List item.  Also, the up and down arrows
  20. **    scroll through the list.
  21. ** 4) Window scrollbars are handled.
  22. */
  23.  
  24.  
  25.  
  26. /*****************************************************************************/
  27.  
  28.  
  29.  
  30. #include "DTS.Lib2.h"
  31. #include "DTS.Lib.protos.h"
  32.  
  33. #include "ListControlProcs.h"
  34. #include "TextEditControlProcs.h"
  35. #include "Utilities.h"
  36.  
  37. static short    HandleScrollEvent(WindowPtr window, EventRecord *event);
  38.  
  39.  
  40.  
  41. /*****************************************************************************/
  42.  
  43.  
  44.  
  45. static FileRecHndl    gFrHndl;
  46. static Rect            gScrollRct;
  47. static Point        gKeepOrg;
  48. static Boolean        gVert;
  49. extern short        gBeginUpdateNested;
  50.  
  51. static pascal void    ScrollActionProc(ControlHandle scrollCtl, short part);
  52.  
  53.  
  54.  
  55.  
  56. /*****************************************************************************/
  57. /*****************************************************************************/
  58. /*****************************************************************************/
  59.  
  60.  
  61.  
  62. /* This function converts a control number to a control handle.  The function
  63. ** simply walks the window's control list counting down until it has reached
  64. ** the right control number.  It also returns the number of controls traversed.
  65. ** While often this will be the same as the control number passed in, if the
  66. ** number passed in is greater than the number of controls in the list, then
  67. ** the number returned is the number of controls in the list. */
  68.  
  69. #pragma segment Controls
  70. short    CNum2Ctl(WindowPtr window, short ctlNum, ControlHandle *ctl)
  71. {
  72.     short    numCtls;
  73.  
  74.     *ctl = nil;
  75.     if (!ctlNum) return(0);
  76.  
  77.     *ctl = ((WindowPeek)window)->controlList;
  78.     for (numCtls = 1; --ctlNum; ++numCtls) {
  79.         if (!*ctl) break;
  80.         *ctl = (**ctl)->nextControl;
  81.     }
  82.  
  83.     return(numCtls);
  84. }
  85.  
  86.  
  87.  
  88. /*****************************************************************************/
  89.  
  90.  
  91.  
  92. /* This function converts a control handle to a control number.  The function
  93. ** simply walks the window's control list and counts how many controls it
  94. ** has to traverse before finding the target control.  The smallest control
  95. ** number that can be returned is 1.  This makes control numbers similar to
  96. ** dialog item numbers. */
  97.  
  98. #pragma segment Controls
  99. short    Ctl2CNum(ControlHandle ctl)
  100. {
  101.     ControlHandle    nextCtl;
  102.     short            ctlNum;
  103.  
  104.     if (!ctl) return(0);
  105.  
  106.     nextCtl = ((WindowPeek)(*ctl)->contrlOwner)->controlList;
  107.     for (ctlNum = 0;;) {
  108.         if (!nextCtl) break;
  109.         ++ctlNum;
  110.         if (ctl == nextCtl) break;
  111.         nextCtl = (*nextCtl)->nextControl;
  112.     }
  113.     return(ctlNum);
  114. }
  115.  
  116.  
  117.  
  118. /*****************************************************************************/
  119.  
  120.  
  121.  
  122. /* This function reactivates the last active TextEdit or List control for
  123. ** the indicated window. */
  124.  
  125. #pragma segment Controls
  126. void    DoCtlActivate(WindowPtr window)
  127. {
  128.     BeginContent(window);
  129.  
  130.     if ((*gclFindActive)(window))        /* If the last item active was */
  131.         (*gclWindActivate)(window);        /* a List, then reactivate it. */
  132.     else
  133.         (*gcteWindActivate)(window);    /* Otherwise, reactivate last TextEdit control. */
  134.  
  135.     EndContent(window);
  136. }
  137.  
  138.  
  139.  
  140. /*****************************************************************************/
  141.  
  142.  
  143.  
  144. /* This function returns all the checkBox values into the dsignated array.
  145. ** The function walks the control list, and when it finds a checkBox control,
  146. ** it gets the control value and places it in the next position in the array.
  147. ** This allows a single call to retrieve all the checkBox values at once. */
  148.  
  149. #pragma segment Controls
  150. void    GetCheckBoxValues(WindowPtr window, Boolean checkBoxVal[])
  151. {
  152.     ControlHandle    nextCtl;
  153.     short            checkBoxIndx;
  154.  
  155.     nextCtl = ((WindowPeek)window)->controlList;
  156.     for (checkBoxIndx = 0;;) {
  157.         if (!nextCtl) return;
  158.         if (GetButtonVariant(nextCtl) == checkBoxProc)
  159.             checkBoxVal[checkBoxIndx++] = GetCtlValue(nextCtl);
  160.         nextCtl = (*nextCtl)->nextControl;
  161.     }
  162. }
  163.  
  164.  
  165.  
  166. /*****************************************************************************/
  167.  
  168.  
  169.  
  170. /* This function returns which radio button is selected for a particular
  171. ** family of radio buttons.  It finds the radio button of the target family
  172. ** with the lowest control number and it subtracts this number from the
  173. ** selected radio button of the same family.  This gives a relative radio
  174. ** button number as a return result.  This way the position of the family
  175. ** of radio buttons can change in the window and the return result is the
  176. ** same.  The family number is stored in the control's refCon field. */
  177.  
  178. #pragma segment Controls
  179. short    GetRadioButtonChoice(WindowPtr window, short famNum)
  180. {
  181.     ControlHandle    nextCtl;
  182.     short            ctlNum, firstInFam;
  183.  
  184.     nextCtl = ((WindowPeek)window)->controlList;
  185.     for (ctlNum = 0, firstInFam = -1;;) {
  186.         if (!nextCtl) return(-1);        /* If a proper radio button family was
  187.                                         ** passed in, this can't happen.  The
  188.                                         ** -1 is an error that indicates that
  189.                                         ** the requested family didn't exist,
  190.                                         ** or that there was no selected
  191.                                         ** radio of the requested family. */
  192.         ++ctlNum;
  193.         if (GetButtonVariant(nextCtl) == radioButProc) {
  194.             if (GetCRefCon(nextCtl) == famNum) {
  195.                 if (firstInFam == -1)
  196.                     firstInFam = ctlNum;
  197.                 if (GetCtlValue(nextCtl)) return(ctlNum - firstInFam);
  198.             }
  199.         }
  200.         nextCtl = (*nextCtl)->nextControl;
  201.     }
  202. }
  203.  
  204.  
  205.  
  206. /*****************************************************************************/
  207.  
  208.  
  209.  
  210. /* This function currently handles events for TextEdit, List, and button
  211. ** controls in a window.  It also handles the window scrollbars and
  212. ** scrolling of the window. */
  213.  
  214. #pragma segment Controls
  215. short    IsCtlEvent(WindowPtr window, EventRecord *event, ControlHandle *retCtl, short *retAction)
  216. {
  217.     RgnHandle        frameRgn;
  218.     TEHandle        te, teNext;
  219.     ListHandle        list, listNext;
  220.     ControlHandle    ctl, activeCtl, teCtl, listCtl, nextCtl;
  221.     short            what, ctlNum, key, modifiers, mode, action;
  222.     Boolean            hitFrame, hitScrollBar;
  223.     Point            clickLoc;
  224.     CTEDataHndl        teData;
  225.     CLDataHndl        listData;
  226.  
  227.     action = 0;
  228.  
  229.     if (retCtl)
  230.         *retCtl = nil;
  231.     if (retAction)
  232.         *retAction = 0;
  233.  
  234.     if ((what = event->what) == mouseDown) {
  235.  
  236.         frameRgn = DoCalcScrollRgn(window);
  237.         hitFrame = PtInRgn(event->where, frameRgn);
  238.         DisposeRgn(frameRgn);
  239.         if (hitFrame) return(HandleScrollEvent(window, event));
  240.             /* If window scrollbar is clicked on, handle the window scroll event. */
  241.  
  242.         BeginContent(window);
  243.         clickLoc = event->where;
  244.         GlobalToLocal(&clickLoc);
  245.  
  246.         (*gcteCtlHit)();    /* Clear CTECtl defProc's last hit CTECtl. */
  247.         (*gclCtlHit)();        /* Clear CLCtl defProc's last hit CLCtl. */
  248.  
  249.         if (WhichControl(clickLoc, window, &ctl)) {
  250.             /* WhichControl also finds inactive controls.  We need this for scrollbars.
  251.             ** If an inactive scrollbar is hit, we should activate the related
  252.             ** TextEdit or List control. */
  253.  
  254.             hitScrollBar = IsScrollBar(ctl);
  255.                 /* The List controls and TextEdit controls may have scrollbars.
  256.                 ** Find out if a scrollbar was pressed, because it may belong
  257.                 ** to a TextEdit or List control. */
  258.  
  259.             FindControl(clickLoc, window, &ctl);
  260.                 /* WhichControl doesn't call the scrollProc.  FindControl does.
  261.                 ** We need it called so we can determine below if a TextEdit or
  262.                 ** List control was hit.  CTECtlHit() and CLCtlHit() return
  263.                 ** the last hit respective control. */
  264.  
  265.             ctlNum = Ctl2CNum(ctl);
  266.  
  267.             if ((hitScrollBar) || ((*gcteCtlHit)())) {
  268.                     /* This test is for speed.  CTEClick would find out if a TextEdit
  269.                     ** control handled the mouse click, but not as fast as we would
  270.                     ** like.  The above test determines if it is worth investigating. */
  271.  
  272.                 if ((*gcteClick)(window, event, &action)) {    /* If click is for TextEdit control... */
  273.                     if (list = (*gclFindActive)(window))
  274.                         (*gclActivate)(false, list);
  275.                             /* If old active control was a List control, deactivate it.
  276.                             ** The TextEdit control doesn't know how to do this. */
  277.                     if (action == -1) {
  278.                         teCtl  = (*gcteViewFromTE)(CTEFindActive(window));
  279.                         teData = (CTEDataHndl)(*teCtl)->contrlData;
  280.                         mode   = (*teData)->mode;
  281.                         if (!(mode & cteTwoStep))
  282.                             (*gcteClick)(window, event, &action);
  283.                     }
  284.                     EndContent(window);
  285.                     if (retCtl)
  286.                         *retCtl = ctl;                /* Return the TextEdit control. */
  287.                     if (retAction)
  288.                         *retAction = action;        /* Return action taken. */
  289.                     return(ctlNum);
  290.                 }
  291.             }
  292.  
  293.             if ((hitScrollBar) || ((*gclCtlHit)())) {
  294.                     /* This test is for speed.  CLClick would find out if a List
  295.                     ** control handled the mouse click, but not as fast as we would
  296.                     ** like.  The above test determines if it is worth investigating. */
  297.  
  298.                 if ((*gclClick)(window, event, &action)) {    /* If click is for List control... */
  299.                     if (te = (*gcteFindActive)(window))
  300.                         (*gcteActivate)(false, te);
  301.                             /* If old active control was a TextEdit control, deactivate it.
  302.                             ** The List control doesn't know how to do this. */
  303.                     if (action == -1) {        /* Just activated a List control... */
  304.                         listCtl  = (*gclViewFromList)((*gclFindActive)(window));
  305.                         listData = (CLDataHndl)(*listCtl)->contrlData;
  306.                         mode     = (*listData)->mode;
  307.                         if (!(mode & clTwoStep))
  308.                             (*gclClick)(window, event, &action);
  309.                     }
  310.                     EndContent(window);
  311.                     if (retCtl)
  312.                         *retCtl = ctl;                /* Return the List control. */
  313.                     if (retAction)
  314.                         *retAction = action;        /* Return action taken. */
  315.                     return(ctlNum);
  316.                 }
  317.             }
  318.  
  319.             action = 0;
  320.             if (!ctl) {
  321.                 EndContent(window);
  322.                 if (retCtl)
  323.                     *retCtl = ctl;
  324.                 if (retAction)
  325.                     *retAction = action;
  326.                 return(ctlNum);
  327.             }
  328.  
  329.             if (TrackControl(ctl, clickLoc, (ProcPtr)-1)) {        /* Handle other controls. */
  330.  
  331.                 switch(GetButtonVariant(ctl)) {
  332.                     case pushButProc:
  333.                         break;
  334.                     case checkBoxProc:
  335.                         SetCtlValue(ctl, GetCtlValue(ctl) ^ 1);        /* Toggle checkBox value. */
  336.                         break;
  337.                     case radioButProc:
  338.                         nextCtl = ((WindowPeek)window)->controlList;
  339.                             /* The below loop walks the control list for the window and
  340.                             ** finds radio buttons of the correct family number.  If
  341.                             ** the found radio button is the one that was clicked on,
  342.                             ** the value is set true, otherwise it is set false. */
  343.                         for (; nextCtl; nextCtl = (*nextCtl)->nextControl) {
  344.                             if (GetButtonVariant(nextCtl) == radioButProc)
  345.                                 if (GetCRefCon(nextCtl) == GetCRefCon(ctl))
  346.                                     SetCtlValue(nextCtl, (nextCtl == ctl));
  347.                         }
  348.                         break;
  349.                 }
  350.             }
  351.             else {
  352.                 ctl = nil;
  353.                 ctlNum = 0;
  354.             }
  355.  
  356.             EndContent(window);
  357.             if (retCtl)
  358.                 *retCtl = ctl;
  359.             if (retAction)
  360.                 *retAction = action;
  361.             return(ctlNum);
  362.         }
  363.  
  364.         EndContent(window);
  365.         return(0);
  366.     }
  367.  
  368.     if ((what == keyDown) || (what == autoKey)) {        /* If event was keypress... */
  369.  
  370.         modifiers = event->modifiers;
  371.         if (modifiers & cmdKey) return(0);
  372.             /* Not our job to handle this one. */
  373.  
  374.         key = event->message & charCodeMask;
  375.  
  376.         if (key == chTab) {        /* If tab... */
  377.  
  378.             teNext    = nil;
  379.             listNext  = nil;
  380.             activeCtl = nil;
  381.  
  382.             if (te   = (*gcteFindActive)(window))
  383.                 activeCtl = (*gcteViewFromTE)(te);
  384.             if (list = (*gclFindActive)(window))
  385.                 activeCtl = (*gclViewFromList)(list);
  386.                     /* Find what the active control is. */
  387.  
  388.             if (!(teCtl = (*gcteNext)(window, &teNext, activeCtl)))
  389.                 teCtl = (*gcteNext)(window, &teNext, nil);
  390.                     /* Find the next TextEdit control from the active control. */
  391.  
  392.             if (!(listCtl = (*gclNext)(window, &listNext, activeCtl)))
  393.                 listCtl = (*gclNext)(window, &listNext, nil);
  394.                     /* Find the next List control from the active control. */
  395.  
  396.             if ((!teNext) && (!listNext)) return(0);
  397.                 /* No TextEdit or List controls in window, so we are done. */
  398.  
  399.             if (!activeCtl)
  400.                 nextCtl = ((WindowPeek)window)->controlList;
  401.             else
  402.                 nextCtl = (*activeCtl)->nextControl;
  403.                     /* At this point we probably have the following information:
  404.                     **   1) Active control.
  405.                     **   2) First TextEdit control after the active control.
  406.                     **   3) First List control after the active control.
  407.                     ** What we want to do is determine if the TextEdit control or
  408.                     ** the List control is closest to the active control.
  409.                     ** We may not have a currently active control, so in that case
  410.                     ** we will start at the beginning of the window control list. */
  411.  
  412.             for (;;) {
  413.                 if (!nextCtl)
  414.                     nextCtl = ((WindowPeek)window)->controlList;
  415.  
  416.                 if (nextCtl == teCtl) {        /* Activate a TextEdit control... */
  417.                     BeginContent(window);    /* Clip out window scrollbars and growIcon. */
  418.                     if (list)
  419.                         (*gclActivate)(false, list);
  420.                     (*gcteActivate)(true, teNext);
  421.                     teData = (CTEDataHndl)(*teCtl)->contrlData;
  422.                     if ((*teData)->mode & cteTabSelectAll)
  423.                         (*gcteSetSelect)(0, (*teNext)->teLength, teNext);
  424.                             /* If the "select all TextEdit text when tabbed into" bit is
  425.                             ** set, then do that very thing. */
  426.                     EndContent(window);        /* Remove the clipping. */
  427.                     if (retCtl)
  428.                         *retCtl = teCtl;
  429.                     if (retAction)
  430.                         *retAction = action;
  431.                     return(Ctl2CNum(teCtl));
  432.                 }
  433.  
  434.                 if (nextCtl == listCtl) {
  435.                     BeginContent(window);    /* Clip out window scrollbars and growIcon. */
  436.                     if (te)
  437.                         (*gcteActivate)(false, te);
  438.                     (*gclActivate)(true, listNext);
  439.                     EndContent(window);        /* Remove the clipping. */
  440.                     if (retCtl)
  441.                         *retCtl = listCtl;
  442.                     if (retAction)
  443.                         *retAction = action;
  444.                     return(Ctl2CNum(listCtl));
  445.                 }
  446.                 nextCtl = (*nextCtl)->nextControl;
  447.             }
  448.         }
  449.  
  450.         if (te = (*gcteFindActive)(window)) {    /* If TextEdit control is active... */
  451.             BeginContent(window);
  452.             (*gcteKey)(window, event);            /* Allow key to be processed by the TextEdit control. */
  453.             action = 1;
  454.             EndContent(window);
  455.             ctl = (*gcteViewFromTE)(te);
  456.             if (retCtl)
  457.                 *retCtl = ctl;
  458.             if (retAction)
  459.                 *retAction = action;
  460.             return(Ctl2CNum(ctl));
  461.         }
  462.  
  463.         if (list = (*gclFindActive)(window)) {        /* If List control is active... */
  464.             BeginContent(window);
  465.             (*gclKey)(window, event);
  466.             EndContent(window);
  467.             ctl = (*gclViewFromList)(list);
  468.             if (retCtl)
  469.                 *retCtl = ctl;
  470.             if (retAction)
  471.                 *retAction = action;
  472.             return(Ctl2CNum(ctl));
  473.         }
  474.     }
  475.  
  476.     return(0);
  477. }
  478.  
  479.  
  480.  
  481. /*****************************************************************************/
  482.  
  483.  
  484.  
  485. #pragma segment Controls
  486. static short    HandleScrollEvent(WindowPtr window, EventRecord *event)
  487. {
  488.     WindowPtr        oldPort;
  489.     Point            clickLoc;
  490.     short            part;
  491.     ControlHandle    ctl;
  492.     short            value, h, v;
  493.     RgnHandle        updateRgn;
  494.  
  495.     GetPort(&oldPort);
  496.     SetPort(window);
  497.     gScrollRct = window->portRect;
  498.  
  499.     gKeepOrg.h = gScrollRct.left;
  500.     gKeepOrg.v = gScrollRct.top;
  501.  
  502.     SetOrigin(0, -16384);
  503.     clickLoc = event->where;
  504.     GlobalToLocal(&clickLoc);
  505.         /* Scrollbars for window are offset -16384 vertically.  Get a local
  506.         ** coordinate that corresponds to this negative space. */
  507.  
  508.     if (!(part = FindControl(clickLoc, window, &ctl))) {
  509.         SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  510.         SetPort(oldPort);
  511.         return(kScrollEvent);
  512.     }
  513.  
  514.     gFrHndl = (FileRecHndl)GetWRefCon(window);
  515.     if ((*gFrHndl)->fileState.vScroll)
  516.         gScrollRct.right  -= 15;
  517.     if ((*gFrHndl)->fileState.hScroll)
  518.         gScrollRct.bottom -= 15;
  519.  
  520.     gScrollRct.left += (*gFrHndl)->fileState.leftSidebar;
  521.     gScrollRct.top  += (*gFrHndl)->fileState.topSidebar;
  522.  
  523.     gVert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
  524.     switch (part) {
  525.         case inThumb:
  526.             value = GetCtlValue(ctl);
  527.             SetOrigin(0, -16384);
  528.             part = TrackControl(ctl, clickLoc, nil);
  529.             SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  530.             if (part) {
  531.                 value -= GetCtlValue(ctl);
  532.                     /* Value now has CHANGE in position.  if position changed, scroll. */
  533.                 if (value) {
  534.                     h = v = 0;
  535.                     if (gVert)
  536.                         v = value;
  537.                     else
  538.                         h = value;
  539.                     ScrollRect(&gScrollRct, h, v, updateRgn = NewRgn());
  540.                     InvalRgn(updateRgn);
  541.                     DisposeRgn(updateRgn);
  542.                     DoScrollFrame(window, h, v);
  543.                 }
  544.             }
  545.             break;
  546.         default:
  547.             SetOrigin(0, -16384);
  548.             TrackControl(ctl, clickLoc, (ProcPtr)ScrollActionProc);
  549.             SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  550.             break;
  551.     }
  552.  
  553.     AdjustScrollBars(window);
  554.  
  555.     SetPort(oldPort);
  556.     return(kScrollEvent);
  557. }
  558.  
  559.  
  560.  
  561. /*****************************************************************************/
  562. /*****************************************************************************/
  563.  
  564.  
  565.  
  566. #pragma segment Controls
  567. static pascal void    ScrollActionProc(ControlHandle scrollCtl, short part)
  568. {
  569.     WindowPtr    window;
  570.     short        delta, value, h, v;
  571.     short        oldValue, max;
  572.     Point        org;
  573.     RgnHandle    updateRgn, contPart, framePart;
  574.  
  575. Rect r;
  576. SetRect(&r, -16000, -16000, 16000, 16000);
  577.  
  578.     GetPort(&window);
  579.  
  580.     if (part) {                        /* If it was actually in the control. */
  581.  
  582.         switch (part) {
  583.             case inUpButton:
  584.             case inDownButton:        /* One line. */
  585.                 delta = (gVert) ? (*gFrHndl)->fileState.vArrowVal : (*gFrHndl)->fileState.hArrowVal;
  586.                 break;
  587.             case inPageUp:            /* One page. */
  588.             case inPageDown:
  589.                 delta = (gVert) ? (*gFrHndl)->fileState.vPageVal : (*gFrHndl)->fileState.hPageVal;
  590.                 break;
  591.         }
  592.  
  593.         if ( (part == inUpButton) || (part == inPageUp) )
  594.             delta = -delta;        /* Reverse direction for an upper. */
  595.  
  596.         value = (oldValue = GetCtlValue(scrollCtl)) + delta;
  597.         if (value < 0)
  598.             value = 0;
  599.         if (value > (max = GetCtlMax(scrollCtl)))
  600.             value = max;
  601.  
  602.         if (value != oldValue) {
  603.  
  604.             SetCtlValue(scrollCtl, value);
  605.             SetOrigin(gKeepOrg.h, gKeepOrg.v);
  606.             h = oldValue - value;
  607.             v = 0;
  608.             if (gVert) {
  609.                 v = h;
  610.                 h = 0;
  611.             }
  612.  
  613.             ScrollRect(&gScrollRct, h, v, updateRgn = NewRgn());
  614.             InvalRgn(updateRgn);
  615.             DisposeRgn(updateRgn);
  616.             DoScrollFrame(window, h, v);
  617.  
  618.             DoUpdateSeparate(window, &contPart, &framePart);
  619.             if (contPart) {
  620.                 CopyRgn(contPart, ((WindowPeek)window)->updateRgn);
  621.                 DisposeRgn(contPart);
  622.                 ++gBeginUpdateNested;
  623.                 BeginUpdate(window);
  624.                 GetContentOrigin(window, &org);
  625.                 SetOrigin(org.h, org.v);
  626.                 DoImageDocument(gFrHndl);
  627.                 EndUpdate(window);
  628.                 --gBeginUpdateNested;
  629.             }
  630.             if (framePart) {
  631.                 CopyRgn(framePart, ((WindowPeek)window)->updateRgn);
  632.                 DisposeRgn(framePart);
  633.             }
  634.  
  635.             SetOrigin(0, -16384);
  636.         }
  637.     }
  638. }
  639.  
  640.  
  641.  
  642.